/****************************************************************
irrEventManager
Copyright (C) 2007-2008 Keith Holbrook
This file is part of "irrEventManager".
For conditions of distribution and use, see copyright notice in irrEventManagerr.h

*****************************************************************/

#include "CEventEx.h"
#include "IGUIContextMenu.h"
#include "..\Debug.h"

namespace irr
{

        u32 CEventEx::getReceiverCount()
        {
            u32 count=0;
            for (u32 i=0; i< receivers.size();i++)
                if (receivers[i])
                    count++;
            return count;

        }

        void CEventEx::removeAll()
        {
            for (u32 i=0; i < receivers.size();i++)
                if(receivers[i])
                   receivers[i]->drop();
            receivers.clear();
            ids=999;
        }

        //!add a new receiver to the list called on the corresponding  event
         bool CEventEx::add(IEventRecEx* r,s32 item)
        {
            if (!r)
                return 0;
            bool foundEmptySlot = 0;
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] == r)
                    return 0;
                if (!receivers[i])
                {
                    receivers[i] = r;
                    foundEmptySlot =1;
                    break;
                }
            }
            if (!foundEmptySlot)
                receivers.push_back(r);

            if (r->getID()<1)
            {
                r->setID(getId()) ;

            }
            return 1;
        }

        //!remove receiver
        void CEventEx::remove(IEventRecEx* r)
        {
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] && (receivers[i] == r))
                {
                    receivers[i]->drop();
                    receivers[i] =0;
                }
            }

        }

         void CEventEx::removeByCaller(void* caller)
        {
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] && (receivers[i]->getCaller() == caller))
                {
                    receivers[i]->drop();
                    receivers[i] =0;
                }

            }
        }

         void CEventEx::removeByData(void* dat)
        {
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] && ( receivers[i]->getData() == dat))
                {
                    receivers[i]->drop();
                    receivers[i] =0;
                }

            }
        }

         void CEventEx::removeByObject(void* obj)
        {
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] && ( receivers[i]->getObj() == obj) )
                {
                    receivers[i]->drop();
                    receivers[i] =0;
                }

            }
        }

         void CEventEx::removeById(s32 id)
        {
            for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] && ( receivers[i]->getID() == id) )
                {
                    receivers[i]->drop();
                    receivers[i] =0;
                }

            }
        }

        ///call ALL receivers until 1 returns true
         bool CEventEx::doEvent(const SEvent& ev)
        {
            for ( u32 i=0 ; i<receivers.size();i++)
            {
                if (receivers[i] &&  receivers[i]->doEvent(ev) )
                    return true;

            }
            return 0;
        }


/// this is probably buggy

        //!add a new receiver to the list called on the corresponding  event
         bool CGuiEventEx::add(IEventRecEx* r,s32 item)
        {
            //DEBUG_PRINT("CGUIEventEx::add called\n");
            if (!r || !r->getCaller())
               return 0;

            if (guiEventType == gui::EGET_MENU_ITEM_SELECTED && ((gui::IGUIElement*)(r->getCaller()))->getType() != gui::EGUIET_CONTEXT_MENU)
            {
                DEBUG_PRINT("Error in CGuiEventEx line 153.\n \
                 Gui element type passed to EGET_MENU_ITEM_SELECTED Event add() function\n \
                   arg should be type: EGUIET_CONTEXT_MENU\n");
                delete r;
                return 0;

            }

            bool foundEmptySlot = 0;
           for (u32 i=0; i< receivers.size();i++)
            {
                if (receivers[i] == r)
                    return 0;
                if (!receivers[i])
                {
                    receivers[i] = r;
                    foundEmptySlot =1;
                    break;
                }
            }
            if (!foundEmptySlot)
                receivers.push_back(r);

            gui::IGUIElement* el = (gui::IGUIElement*)r->getCaller();
            s32 id=0;
            ///Is it a context menu?
            if (guiEventType == gui::EGET_MENU_ITEM_SELECTED )
            {

                gui::IGUIContextMenu* cm = (gui::IGUIContextMenu*)el;

                ///if menu item# NOT specified
                 if (item < 0 || item >= (s32)cm->getItemCount() )
                    item = cm->getItemCount()-1;

                 ///see if command id is already set
                 id = cm->getItemCommandId(item);
                 ///if not get new one
                 if(id < 1)
                 {
                      ///see if it wass set in the reciever
                     id = r->getID();
                      ///if not get new one
                     if(id < 1 )
                        id = getId();

                  }

                 r->setID(id);
                 ///set the unique id as the command id
                 cm->setItemCommandId(item,id) ;

            }
            else
           ///if not a menu
            {
                ///see if an id was set already
                id = el->getID();
                if (id<1)
                {
                    ///see if an id > 1 was set in the reciever already
                    id = r->getID();
                    if (id<1)///if not set new id
                       id = getId();
                }
                ///else get new id
                r->setID(id);
                ///set id
                el->setID(id);


            }
            return 1;

        }

/// For gui events
        bool CGuiEventEx::doEvent(const SEvent& ev)
        {
            s32 id =-1;
            if (ev.GUIEvent.EventType != guiEventType)
                return 0;
            switch (guiEventType)
            {

//          case gui::EGET_ELEMENT_FOCUS_LOST:  break;
//			case gui::EGET_ELEMENT_FOCUSED:   break;
//			case gui::EGET_ELEMENT_HOVERED:   break;
//			case gui::EGET_ELEMENT_LEFT:   break;
//			case gui::EGET_ELEMENT_CLOSED:   break;
//			case gui::EGET_BUTTON_CLICKED:   break;
//			case gui::EGET_SCROLL_BAR_CHANGED:   break;
//			case gui::EGET_CHECKBOX_CHANGED:   break;
//			case gui::EGET_LISTBOX_CHANGED:   break;
//			case gui::EGET_LISTBOX_SELECTED_AGAIN:   break;
//			case gui::EGET_FILE_SELECTED:   break;
//          case gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED:   break;
//			case gui::EGET_MESSAGEBOX_YES:   break;
//			case gui::EGET_MESSAGEBOX_NO:   break;
//			case gui::EGET_MESSAGEBOX_OK:   break;
//			case gui::EGET_MESSAGEBOX_CANCEL:   break;
//			case gui::EGET_EDITBOX_ENTER:   break;
//			case gui::EGET_TAB_CHANGED:   break;
            case  gui::EGET_MENU_ITEM_SELECTED :
            {
                gui::IGUIContextMenu* menu = (gui::IGUIContextMenu*)ev.GUIEvent.Caller;
                id = menu->getItemCommandId(menu->getSelectedItem());

            }
            break;
//			case gui::EGET_COMBO_BOX_CHANGED:   break;
//			case gui::EGET_SPINBOX_CHANGED:   break;
//			case gui::EGET_TABLE_CHANGED:   break;
//			case gui::EGET_TABLE_HEADER_CHANGED:   break;
//			case gui::EGET_TABLE_SELECTED_AGAIN:   break;

            default:
                id = ev.GUIEvent.Caller->getID();
                break;
            }

            for ( u32 i=0 ; i<receivers.size(); i++)
            {
				if (receivers[i] && (receivers[i]->getID()==id  )) {
					IGUIElement *c = (IGUIElement*)receivers[i]->getCaller();
					IGUIElement *b = (IGUIElement*)ev.GUIEvent.Caller;
					if(c == b || c == NULL) {
						if(receivers[i]->doEvent(ev))
							return true;
					}
				}
			}
            return 0;

        }

}
